/*=============================================================

PROGRAMMING TECHNIQUES FOR SUPERCOMPUTERS

Assignment Number 3

Task 2 - Optimizing loop code

=============================================================*/

#include <stdio.h>
#include "timing.hh"
#include <iostream>
#include <math.h>
#include <fstream>
#include <iostream>

double timeStamp()
{ 
  struct timeval tp;
  gettimeofday(&tp, NULL); 
  return((double)(tp.tv_sec + tp.tv_usec/1000000.0)); 
}

int main(int argc, char *argv[]) 
{
	double wcTimeStart,wcTimeEnd,cpuTimeStart,cpuTimeEnd,wcTime, cpTime;	
	int N =8192;
	
	//allocating 2D array (on heap) by using pointers instead of on stack
	double **mat = new double*[N];
	double **s = new double*[N];
	for (int i = 0; i < N; ++i)
	{
	   mat[i] = new double[N];
	   s[i] = new double[N];
	}
	
	for (int i = 0; i < N; ++i) 
	{
	   for (int j = 0; j < N; ++j)
	   {
	      s[i][j] = 2.0*j+6.313;
	   }
	   
	}

		int repeat =1;
		double runtime =0.;
		double val;
		double inv;
		for (; runtime <0.1; repeat*=2)
		{	
		   
			wcTimeStart = timeStamp();
			srand(1);
			for (int r=0; r<repeat; ++r)
			{  
			   val = (double)rand(); //random number
			   // introducing new variable s.t. division has to be computed only once
			   inv = 1./val;
				for (int i = 0; i < N; ++i)
				{
				   for (int j = 0; j < N; ++j)
				   {
				      //array access changed
				      // division changed to multiplication with inverse
					   mat[i][j] = inv * s[i][j];
					}
				}
				if (mat[N-1][N-1] <0.) std::cout << "Dummy Loop Encountered"<< std::endl;
			}
				wcTimeEnd = timeStamp();	
				runtime=wcTimeEnd-wcTimeStart;				
		}
		repeat/=2;
		long noFlops = N*N*repeat;
		double mFlops = noFlops/(runtime*1000000);
		std::cout << "N: " << N << std::endl;
      std::cout << "Performance: " << mFlops << "MFlop/s" << std::endl;
	
	return 0;
}
